//==============================================================================
//
//          DRnd - the pseudo random generator in the ofc-library
//
//               Copyright (C) 2003  Dick van Oudheusden
//  
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2007-07-22 06:21:27 $ $Revision: 1.4 $
//
//==============================================================================

#include "ofc/DRnd.h"

#include "ofc/warning.h"


#if _INTERFACE_

#include <stdint.h>

#include "ofc/config.h"

#include "ofc/DRandomable.h"


// The DRnd class implements a pseudo random generator bases on a linair
// congruential generator. This is the most commonly used type, it is fast 
// but it has some well-known flaws. See @class(DMRnd) and @class(DLRnd) 
// for a better, but slower pseudo random generator.

@interface DRnd : Object <DRandomable>
{
@private
  uint32_t _seed;   // the seed for the generator
}

#endif



#define RND_MAX    (4294967291.0)



@implementation DRnd


//// Constructors

//
// Initialise a non-seeded random generator
//
// @return the object
//

- (DRnd *) init
{
  [super init];

  _seed = 93186752;
  
  return self;
}

//
// Initialise a seeded random generator
//
// @param seed     the seed to be used
// 
// @return the object
//

- (DRnd *) init :(unsigned long) seed
{
  [self init];
  
  [self seed :seed];
  
  return self;
}


//// Member methods

//
// Set the seed for the random generator
// 
// @param seed     the seed for the random generator
//
// @return the object
//

- (DRnd *) seed :(unsigned long) seed
{
  if (seed > 0)
    _seed = (uint32_t) seed;
  else   
    WARNING(DW_INVALID_ARG, "seed");
  
  return self;
}


//// Random generator methods

static uint32_t nextValue(DRnd *self)
{
  self->_seed = 1588635695 * (self->_seed % 2) - 1117695901 * (self->_seed / 2);
  
  return self->_seed;
}

//
// Get the next long from the generator
//  
// @return the next long
//

- (long) nextLong 
{
  return (long)((int32_t)(nextValue(self)));
}

//
// Get the next long inside a range from the generator
// 
// @param from     the start of the range
// @param to       the end of the range
// 
// @return the next long
// 

- (long) nextLong :(long) from :(long) to
{
  return from + (to - from + 1) * ((double) nextValue(self) / RND_MAX);
}

//
// Get the next integer from the generator
//  
// @return the next integer
//

- (int) nextInt
{
  return (int)(nextValue(self));
}

//
// Get the next integer inside a range from the generator
// 
// @param from     the start of the range
// @param to       the end of the range
// 
// @return the next integer (inside the range)
// 

- (int) nextInt :(int) from :(int) to
{
  return from + (int) (to - from + 1) * ((double) nextValue(self) / RND_MAX);
}

//
// Get the next double from the generator (0 <= v < 1)
//  
// @return the next double
//

- (double) nextDouble
{
  return (double) nextValue(self) / RND_MAX;
}

//
// Get the next double from the generator (from <= v < to)
// 
// @param from     the start of the range
// @param to       the end of the range
// 
// @return the next double
// 

- (double) nextDouble :(double) from :(double) to
{
  return from + (to - from) * ((double) nextValue(self) / RND_MAX);
}


@end

/*==========================================================================*/
